
#include <new>
#include <memory>
#include <stdexcept>
#include <cstdlib>
#include <cctype>
#include <string.h>

#include "CgiEnvironment.h"

// ========== Constructor/Destructor

HttpFrame::CgiEnvironment::CgiEnvironment()
{
	readEnvVariables();  
  
	fCookies.clear();
	parseCookies();
}

HttpFrame::CgiEnvironment::~CgiEnvironment()
{}

// Overloaded operators
bool 
HttpFrame::CgiEnvironment::operator== (const CgiEnvironment& env) 		const
{
  bool result;
  
  result =  fServerPort 	== env.fServerPort;
  result &= fContentLength 	== env.fContentLength;
  result &= fUsingHTTPS 	== env.fUsingHTTPS;
  result &= fServerSoftware 	== env.fServerSoftware;
  result &= fServerName 	== env.fServerName;
  result &= fGatewayInterface 	== env.fGatewayInterface;
  result &= fServerProtocol 	== env.fServerProtocol;
  result &= fRequestMethod 	== env.fRequestMethod;
  result &= fPathInfo 		== env.fPathInfo;
  result &= fPathTranslated 	== env.fPathTranslated;
  result &= fScriptName 	== env.fScriptName;
  result &= fQueryString 	== env.fQueryString;
  result &= fRemoteHost 	== env.fRemoteHost;
  result &= fRemoteAddr 	== env.fRemoteAddr;
  result &= fAuthType 		== env.fAuthType;
  result &= fRemoteUser 	== env.fRemoteUser;
  result &= fRemoteIdent 	== env.fRemoteIdent;
  result &= fContentType 	== env.fContentType;
  result &= fAccept 		== env.fAccept;
  result &= fUserAgent 		== env.fUserAgent;
  result &= fPostData 		== env.fPostData;
  result &= fRedirectRequest 	== env.fRedirectRequest;
  result &= fRedirectURL 	== env.fRedirectURL;
  result &= fRedirectStatus 	== env.fRedirectStatus;
  result &= fReferrer 		== env.fReferrer;
  result &= fCookie 		== env.fCookie;

  return result;
}

HttpFrame::CgiEnvironment& 
HttpFrame::CgiEnvironment::operator= (const CgiEnvironment& env)
{
  fServerPort 		= env.fServerPort;
  fContentLength 	= env.fContentLength;
  fUsingHTTPS 		= env.fUsingHTTPS;
  fServerSoftware 	= env.fServerSoftware;
  fServerName 		= env.fServerName;
  fGatewayInterface 	= env.fGatewayInterface;
  fServerProtocol 	= env.fServerProtocol;
  fRequestMethod 	= env.fRequestMethod;
  fPathInfo 		= env.fPathInfo;
  fPathTranslated 	= env.fPathTranslated;
  fScriptName 		= env.fScriptName;
  fQueryString 		= env.fQueryString;
  fRemoteHost 		= env.fRemoteHost;
  fRemoteAddr 		= env.fRemoteAddr;
  fAuthType 		= env.fAuthType;
  fRemoteUser 		= env.fRemoteUser;
  fRemoteIdent 		= env.fRemoteIdent;
  fContentType 		= env.fContentType;
  fAccept 		= env.fAccept;
  fUserAgent 		= env.fUserAgent;
  fPostData 		= env.fPostData;
  fRedirectRequest 	= env.fRedirectRequest;
  fRedirectURL 		= env.fRedirectURL;
  fRedirectStatus 	= env.fRedirectStatus;
  fReferrer 		= env.fReferrer;
  fCookie 		= env.fCookie;

  fCookies.clear();
  parseCookies();

  return *this;
}

std::string
HttpFrame::CgiEnvironment::getenv(const char *varName)
{
  char *var = std::getenv(varName);
  return (0 == var) ? std::string("") : var;
}


void
HttpFrame::CgiEnvironment::parseCookies()
{
	std::string data = fCookie;

	if(false == data.empty()) {
	std::string::size_type pos;
    std::string::size_type oldPos = 0;

	while(true) {
		// find the ';' terminating a name=value pair
    	pos = data.find(";", oldPos);

		// if no ';' was found, the rest of the string is a single cookie
		if(std::string::npos == pos) {
			parseCookie(data.substr(oldPos));
			return;
		}

		// otherwise, the string contains multiple cookies
		// extract it and add the cookie to the list
		parseCookie(data.substr(oldPos, pos - oldPos));
      
		// update pos (+1 to skip ';')
		oldPos = pos + 1;
		}
	}
}

void
HttpFrame::CgiEnvironment::parseCookie(const std::string& data)
{
	// find the '=' separating the name and value
	std::string::size_type pos = data.find("=", 0);

	// if no '=' was found, return
	if(std::string::npos == pos)
    	return;

	// skip leading whitespace - " \f\n\r\t\v"
	std::string::size_type wscount = 0;
	std::string::const_iterator data_iter;
  
	for(data_iter = data.begin(); data_iter != data.end(); ++data_iter,++wscount)
		if(0 == std::isspace(*data_iter))
			break;			
  
	// Per RFC 2091, do not unescape the data (thanks to afm@othello.ch)
	std::string name 	= data.substr(wscount, pos - wscount);
	std::string value 	= data.substr(++pos);

	cookie_iterator iter = fCookies.find( name );
	if ( iter != fCookies.end() ) {
        fCookies.erase( iter );
    }
    fCookies.insert( Cookie_Container::value_type(name, value) );
}

// Read in all the environment variables
void
HttpFrame::CgiEnvironment::readEnvVariables()
{
  fServerSoftware 	= getenv("SERVER_SOFTWARE");
  fServerName 		= getenv("SERVER_NAME");
  fGatewayInterface 	= getenv("GATEWAY_INTERFACE");
  fServerProtocol 	= getenv("SERVER_PROTOCOL");

  std::string port 	= getenv("SERVER_PORT");
  fServerPort 		= std::atol(port.c_str());

  fRequestMethod 	= getenv("REQUEST_METHOD");
  fPathInfo 		= getenv("PATH_INFO");
  fPathTranslated 	= getenv("PATH_TRANSLATED");
  fScriptName 		= getenv("SCRIPT_NAME");
  fQueryString 		= getenv("QUERY_STRING");
  fRemoteHost 		= getenv("REMOTE_HOST");
  fRemoteAddr 		= getenv("REMOTE_ADDR");
  fAuthType 		= getenv("AUTH_TYPE");
  fRemoteUser 		= getenv("REMOTE_USER");
  fRemoteIdent 		= getenv("REMOTE_IDENT");
  fContentType 		= getenv("CONTENT_TYPE");

  std::string length 	= getenv("CONTENT_LENGTH");
  fContentLength 	= std::atol(length.c_str());

  fAccept 		= getenv("HTTP_ACCEPT");
  fUserAgent 		= getenv("HTTP_USER_AGENT");
  fRedirectRequest 	= getenv("REDIRECT_REQUEST");
  fRedirectURL 		= getenv("REDIRECT_URL");
  fRedirectStatus 	= getenv("REDIRECT_STATUS");
  fReferrer 		= getenv("HTTP_REFERER");
  fCookie 		= getenv("HTTP_COOKIE");

  std::string https 	= getenv("HTTPS");
  if(!strncasecmp(https.c_str(), "on", 2))
    fUsingHTTPS = true;
  else
    fUsingHTTPS = false;


}

